package com.bailun91.auth.shiro;

import com.bailun91.auth.entity.Permission;
import com.bailun91.auth.mapper.PermissionMapper;
import com.bailun91.auth.util.BeanUtil;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 *  Filter 管理器
 * @author tomsun28
 * @date 11:16 2018/2/28
 */
@Component
public class ShiroFilterChainManager {

    @Autowired
    PermissionMapper permissionMapper;

    public Map<String, String> loadFilterChainDefinitions() {

        // 权限控制map.从数据库获取
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // druid数据源监控页面不拦截
        filterChainDefinitionMap.put("/druid/**", "anon");
        // 配置退出过滤器，其中具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
        // 设置公共的页面或者请求不拦截，例如首页
        filterChainDefinitionMap.put("/pub/**", "anon");
        // 访问401和404页面不通过我们的Filter
        filterChainDefinitionMap.put("/401", "anon");
        filterChainDefinitionMap.put("/403", "anon");
        filterChainDefinitionMap.put("/404", "anon");

        //上面是一些固定的路径可以直接写死在代码中，或者全部放数据库
        // 但是如果需要动态分配权限的话，那么可以把相关的权限放在数据库，
        // 通过加载数据库存储的权限来实现动态分配权限，因为存在数据库的权限是可以通过增删改接口前端随时更改的，
        // 这样可以实现权限的动态更新
        List<Permission> permissionList = permissionMapper.findAllPermissions();
        for (Permission permission: permissionList) {
            String perms = "perms" + "[" + permission.getPerms() + "]";
            filterChainDefinitionMap.put(permission.getUrl(),"jwt,"+ perms);
        }

        // 所有请求通过我们自己的JWT Filter，最好是放最后
        filterChainDefinitionMap.put("/**", "noSessionCreation,jwt");

        return filterChainDefinitionMap;
    }


    /**
     * 在对角色进行增删改操作时，需要调用此方法进行动态刷新
     */

    public void updatePermission() {

        ShiroFilterFactoryBean shiroFilterFactoryBean =  BeanUtil.getBean(ShiroFilterFactoryBean.class);
        synchronized (this) {
            AbstractShiroFilter shiroFilter;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            } catch (Exception e) {
                throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
            }

            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();

            // 清空老的权限控制
            manager.getFilterChains().clear();

            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            shiroFilterFactoryBean.setFilterChainDefinitionMap(loadFilterChainDefinitions());
            // 重新构建生成
            Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim()
                        .replace(" ", "");
                manager.createChain(url, chainDefinition);
            }
        }
    }

}
